home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / libs / phigs / ptk.lha / ptk / source / library / hash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-01  |  41.7 KB  |  1,440 lines

  1. /*----------------------------------------------------------------------------
  2.  
  3.  Module name: hash strings to integers.
  4.  
  5.  Author: S. Larkin.
  6.  
  7.  Function: Contains routines to manipulate a table of hashtables.
  8.  The routines allocate unique integer id`s to strings 
  9.  and also allow retrieval of these strings via their unique id`s.
  10.  
  11.  Dependencies: machine.h.
  12.  
  13.  External function list: 
  14.       ptk_inithashtables
  15.       ptk_idtostring
  16.       ptk_delstring
  17.       ptk_delhashtable
  18.       ptk_stringtoid                  
  19.       ptk_stringused
  20.       ptk_inqstrings
  21.       ptk_inqhashtables
  22.       ptk_storehashtable
  23.       ptk_storeallhashtables
  24.       ptk_restorehashtable
  25.       ptk_restoreallhashtables
  26.       ptk_createhashtable
  27.       ptk_hashtableused
  28.  
  29.  Internal function list: 
  30.       searchforstring
  31.       getnextstrid
  32.       freestrid
  33.       hashstring
  34.       parsestring
  35.       stringlength
  36.       outputfreeidlist
  37.       addstring
  38.       addstringtotable
  39.       addtabletotable
  40.       ptk_stringtotable
  41.  
  42.  Hashtables used: all.
  43.  
  44.  Modification history : (Version), (Date), (Name), (Description).
  45.  
  46.  1.0,  18th August 1988,  S. Larkin,  First version.
  47.  
  48.  1.1,  7th November 1988,  S. Larkin, This module now 
  49.  supports a fixed number ( 10 ) of independent hashtables.
  50.  All functions now take a table parameter which specifies 
  51.  which hashing table is being accessed.
  52.  Two new func/proc have been added:
  53.    string_Used which returns TRUE if the supplied
  54.        string has been used in the hashing table.
  55.    Inquire_table which returns details about appropriate
  56.        hashtable.
  57.  
  58.  2.0,  4th January 1991,  G. Williams, Converted from Pascal
  59.  to C. Function names changed to PHIGS Toolkit convention - ptk_xxx.
  60.  There is now no restriction on the number of hashtables, the user
  61.  must call ptk_hashinitialise to initialise a hashtable. Each hashtable
  62.  has a specified range of structure identifiers which is supplied by
  63.  the user.
  64.  
  65.  2.1, 18th March 1991, G. Williams, new strategy - a table of tables.
  66.  
  67.  3.0, June 1992, G. Williams, Converted to ISO PHIGS C.
  68.  
  69. ----------------------------------------------------------------------------*/
  70.  
  71. #include <stdio.h>
  72. #include <ctype.h>
  73. #ifdef SUN
  74. #include <malloc.h>
  75. #endif
  76. #ifdef PEXSI
  77. #include <malloc.h>
  78. #endif
  79. #include <phigs.h>
  80. #include "machine.h"
  81. #include "ptktype.h"
  82. #include "hashtype.h"
  83. #include "perrfns.h"
  84.  
  85. #define NIL   -1
  86.  
  87. #define sizeofhashtable  1009
  88.  
  89. typedef struct ptksstridentry   
  90. {
  91.     char *strdata;
  92.     Pint stringlen;
  93.     Pint uniqint;
  94.     Pint clashptr, prevptr;
  95. } ptksstridentry;
  96.  
  97. typedef Pint ptkahashtablecont[sizeofhashtable];
  98.  
  99. typedef struct ptksfreeint 
  100. {
  101.     Pint freeint;
  102.     struct ptksfreeint *next;
  103. } ptksfreeint;
  104.  
  105. typedef struct ptkshashtable
  106. {
  107.     ptkahashtablecont hashtable;
  108.     Pint numstrings;
  109.     Pint minuniqint;
  110.     Pint maxuniqint;
  111.     ptksstridentry *stridtable;
  112.     ptksfreeint *freeintlist;
  113. } ptkshashtable;
  114.  
  115. typedef struct ptkstableentry
  116. {
  117.     char *strdata;
  118.     Pint stringlen;
  119.     ptkshashtable *tableptr;
  120.     Pint clashptr, prevptr;
  121. } ptkstableentry;
  122.  
  123. typedef struct ptkshashtablelst
  124. {
  125.     ptkahashtablecont hashtable;
  126.     Pint numtables;
  127.     ptkstableentry *tablelist;
  128.     ptksfreeint *freeintlist;
  129. } ptkshashtablelst;
  130.  
  131. static ptkshashtablelst toptable;
  132. static ptkboolean PTKINITHASH = FALSE;
  133.  
  134. /*--------------------------------------------------------------------------*/
  135.  
  136. static Pint hashstring(C(char *)str, C(Pint) strlength)
  137. PreANSI(char *str)
  138. PreANSI(Pint strlength)
  139. /*
  140. ** \blurb{This function returns a hash value in the range 1 to `sizeofhashtable'.}
  141. ** \param{str}{string}
  142. ** \param{strlength}{length of string. }
  143. ** none.
  144. ** return value: hash value of str.
  145. */
  146. {
  147.   Pint i, l, shift;
  148.   unsigned int res, ch;
  149.  
  150.   l = 0;
  151.   res = 0;
  152.   shift = 1;
  153.   for (i = 0; i < strlength; i++) 
  154.   {
  155.     ch = (unsigned int)str[i] * shift;
  156.     res ^= ch;
  157.     l++;
  158.     if (shift == 1)
  159.       shift = 256;
  160.     else
  161.       shift *= 256;
  162.     if (l == 4) 
  163.     {
  164.       l = 0;
  165.       shift = 1;
  166.     }
  167.   }
  168.   return (res % sizeofhashtable + 1);
  169. }  /* hashstring */
  170.  
  171. /*--------------------------------------------------------------------------*/
  172.  
  173. static void searchforstring(C(char *)sname, C(Pint) startentry,
  174.                             C(ptkshashtable *)table, 
  175.                             C(Pint *)foundentry, C(ptkboolean *)isfound)
  176. PreANSI(char *sname) 
  177. PreANSI(Pint startentry)
  178. PreANSI(ptkshashtable *table) 
  179. PreANSI(Pint *foundentry) 
  180. PreANSI(ptkboolean *isfound)
  181. /*
  182. ** \blurb{Searches for the given string in a hashtable.}
  183. ** \param{sname}{string to search for}
  184. ** \param{startentry}{position to start searching for string in string table}
  185. ** \param{table}{hashtable}
  186. ** \param{foundentry}{position in string table of string}
  187. ** \param{isfound}{TRUE if string is in table, FALSE if not}
  188. ** return value: none.
  189. */
  190. {
  191.   Pint nextentry;
  192.   ptksstridentry *entry;
  193.  
  194.   *isfound = FALSE;
  195.     if (startentry != NIL) 
  196.     {
  197.       do 
  198.       {
  199.         entry = &table->stridtable[startentry];
  200.         if (entry->strdata != NULL)
  201.           if (!strncmp(entry->strdata, sname, strlen(entry->strdata)))
  202.         *isfound = TRUE;
  203.         if (!*isfound)
  204.         {  
  205.           /* check next id */
  206.       nextentry = entry->prevptr;
  207.       if (nextentry != NIL)
  208.         startentry = nextentry;
  209.     }
  210.       } while (*isfound != TRUE && nextentry != NIL);
  211.     }
  212.   *foundentry = startentry;
  213. }  /* searchforstring */
  214.  
  215. /*--------------------------------------------------------------------------*/
  216.  
  217. static void searchfortable(C(char *)tabname, C(Pint) startentry,
  218.                             C(Pint *)foundentry, C(ptkboolean *)isfound)
  219. PreANSI(char *tabname) 
  220. PreANSI(Pint startentry)
  221. PreANSI(Pint *foundentry) 
  222. PreANSI(ptkboolean *isfound)
  223. /*
  224. ** \blurb{Searches for the given table name in hashtable table.}
  225. ** \param{tabname}{name of table to search for}
  226. ** \param{startentry}{position to start searching for table in hashtable table}
  227. ** \param{table}{hashtable table}
  228. ** \param{foundentry}{position in hashtable table of table}
  229. ** \param{isfound}{TRUE if table is in hashtable table, FALSE if not}
  230. **
  231. ** return value: none.
  232. */
  233. {
  234.   Pint nextentry;
  235.   ptkstableentry *entry;
  236.  
  237.   *isfound = FALSE;
  238.     if (startentry != NIL) 
  239.     {
  240.       do 
  241.       {
  242.         entry = &toptable.tablelist[startentry];
  243.         if (entry->strdata != NULL)
  244.           if (!strncmp(entry->strdata, tabname, strlen(entry->strdata)))
  245.         *isfound = TRUE;
  246.     if (!*isfound) 
  247.         {  
  248.           /* check next id */
  249.       nextentry = entry->prevptr;
  250.       if (nextentry != NIL)
  251.         startentry = nextentry;
  252.     }
  253.       } while (*isfound != TRUE && nextentry != NIL);
  254.     }
  255.   *foundentry = startentry;
  256. }  /* searchfortable */
  257.  
  258. /*--------------------------------------------------------------------------*/
  259.  
  260. static Pint getnextstrid(C(ptksfreeint **) freelist)
  261. PreANSI(ptksfreeint **freelist)
  262. /*
  263. ** \blurb{Returns next free string id, returns 0 if no more left.}
  264. ** \param{table}{hashtable}
  265. ** return value: next free string identifier.
  266. ** error conditions: table->freeintlist == NULL - no more free string id's.
  267. */
  268. {
  269.   Pint result;
  270.  
  271.   result = 0;
  272.   if (*freelist == NULL) 
  273.   {
  274.     fprintf(stderr, "HashStrings: Run out of integers to allocate\n");
  275.     return result;
  276.   }
  277.   result = (*freelist)->freeint;
  278.   if ((*freelist)->next == NULL)   /* end of list */
  279.     ((*freelist)->freeint)++;   /* make next id free */
  280.   else
  281.     *freelist = (*freelist)->next;
  282.   return result;
  283. }  /* getnextstrid */
  284.  
  285. /*--------------------------------------------------------------------------*/
  286.  
  287. static void freestrid(C(ptksfreeint **) freelist, C(Pint) fid)
  288. PreANSI(ptksfreeint **freelist)
  289. PreANSI(Pint fid)
  290. /*
  291. ** \blurb{Fid is placed on the freeintlist so it can be used again. }
  292. ** \param{table}{hashtable}
  293. ** \param{fid}{string identifier to be made free}
  294. ** special notes: this function is used when a string has been deleted from
  295. ** the string table and it's corresponding string identifier is made
  296. ** available for a new string.
  297. */
  298. {
  299.   ptksfreeint *temp;
  300.  
  301.   temp = (ptksfreeint *)malloc(sizeof(ptksfreeint));
  302.   temp->freeint = fid;
  303.   temp->next = *freelist;
  304.   *freelist = temp;
  305. }  /* freestrid */
  306.  
  307. /*--------------------------------------------------------------------------*/
  308.  
  309. static Pint stringlength(C(char *)str)
  310. PreANSI(char *str)
  311. /*
  312. ** \blurb{Returns length of string up to first ' '(space), '\n' or '\0' 
  313. ** character.}
  314. ** \param{str}{string to find length of}
  315. ** return value: length of string.
  316. ** special notes: The hashstrings algorithm does not permit strings with
  317. ** spaces, hence the search for the first space character. The C library
  318. ** routine `strlen' assumes there is a `\0' character terminating the string,
  319. ** however it is safer to look for a `\n' character aswell.
  320. */
  321. {
  322.   ptkboolean charfound;
  323.   Pint ind;
  324.  
  325.   ind = 0;
  326.   charfound = FALSE;
  327.   while (!charfound) 
  328.   {
  329.     if (str[ind] == '\n' || str[ind] == '\0')
  330.       charfound = TRUE;
  331.     else
  332.       ind++;
  333.   }
  334.   return ind;
  335. }  /* stringlength */
  336.  
  337. /*--------------------------------------------------------------------------*/
  338.  
  339. static void parsestring(C(char *)beforestr, C(char *)afterstr, 
  340.                         C(Pint) strlength)
  341. PreANSI(char *beforestr)
  342. PreANSI(char *afterstr)
  343. PreANSI(Pint strlength)
  344. /*
  345. ** \blurb{All upper case characters are converted to lowercase 
  346. ** and a `\0' character is put on end of the string.}
  347. ** \param{beforestr}{string to be parsed}
  348. ** \param{strlength}{length of parsed string}
  349. ** \param{afterstr}{parsed string}
  350. */
  351. {
  352.   Pint ind;
  353.  
  354.   for (ind = 0; ind < strlength; ind++) 
  355.   {
  356.     if (isupper(beforestr[ind]))
  357.       afterstr[ind] = beforestr[ind] - ('A' - 'a');
  358.     else
  359.       afterstr[ind] = beforestr[ind]; 
  360.   }
  361.   afterstr[ind] = '\0';
  362. }  /* parsestring */
  363.  
  364. /*--------------------------------------------------------------------------*/
  365.  
  366. static ptkboolean addstringtotable(C(ptkshashtable *) table, C(char *) str,
  367.                                 C(Pint *) strint)
  368. PreANSI(ptkshashtable *table)
  369. PreANSI(char *str)
  370. PreANSI(Pint *strint)
  371. /*
  372. ** \blurb{Adds a string entry to the string table of a given
  373. ** hashtable. Reallocates the whole string table if necessary.}
  374. ** \param{table}{hashtable to add string to}
  375. ** \param{str}{string to add to table}
  376. */
  377. {
  378.   ptksstridentry *strentry;
  379.   Pint strlength;
  380.   ptkboolean needrealloc;
  381.  
  382.     /* allocate space for string entry */
  383.     /* if strint < number of strings in list then no need to reallocate */
  384.  
  385.     if (table->freeintlist->next == NULL)
  386.       needrealloc = TRUE;
  387.     else
  388.       needrealloc = FALSE;
  389.  
  390.     *strint = getnextstrid(&table->freeintlist);
  391.     if (*strint > table->maxuniqint)
  392.     {
  393.       fprintf(stderr, "HashStrings: Run out of integers to allocate\n");
  394.       return FALSE;
  395.     }
  396.  
  397.     if (needrealloc)
  398.     {
  399.       table->numstrings++;
  400.       table->stridtable = (ptksstridentry *)realloc(table->stridtable,
  401.                                table->numstrings * sizeof(ptksstridentry));
  402.     }
  403.  
  404.     strlength = strlen(str);
  405.     strentry = (table->stridtable + (*strint - table->minuniqint));
  406.     strentry->strdata = (char *)malloc(strlength + 1);
  407.     strncpy(strentry->strdata, str, (strlength + 1));
  408.     strentry->stringlen = strlength;
  409.     strentry->uniqint = *strint;
  410.     strentry->clashptr = NIL;
  411.     strentry->prevptr = NIL;
  412.     return TRUE;
  413. }  /* addstringtotable */
  414.  
  415. /*--------------------------------------------------------------------------*/
  416.  
  417. static Pint addtabletotable(C(char *) str)
  418. PreANSI(char *str)
  419. /*
  420. ** \blurb{Adds a hashtable to the table of hashtables.
  421. ** Reallocates the whole table of hashtable names if necessary.}
  422. ** \param{table}{table of hashtables}
  423. ** \param{str}{name of new hashtable}
  424. */
  425. {
  426.   ptkstableentry *tabentry;
  427.   Pint stid, strlength;
  428.  
  429.   /* allocate space for string entry */
  430.   /* if stid < number of tables in list then no need to reallocate */
  431.  
  432.   if (toptable.freeintlist->next == NULL)
  433.   {
  434.     toptable.numtables++;
  435.     toptable.tablelist = (ptkstableentry *)realloc(toptable.tablelist,
  436.                          toptable.numtables * sizeof(ptkstableentry));
  437.   }
  438.   stid = getnextstrid(&toptable.freeintlist);
  439.   strlength = strlen(str);
  440.   tabentry = &toptable.tablelist[stid];
  441.   tabentry->strdata = (char *)malloc(strlength + 1);
  442.   strncpy(tabentry->strdata, str, (strlength + 1));
  443.   tabentry->stringlen = strlength;
  444.   tabentry->clashptr = NIL;
  445.   tabentry->prevptr = NIL;
  446.   return stid;
  447. }  /* addtabletotable */
  448.  
  449. /*--------------------------------------------------------------------------*/
  450.  
  451. static void ptk_hashinitialise(C(ptkshashtable *)table, C(Pint) minint, 
  452.                                C(Pint) maxint)
  453. PreANSI(ptkshashtable *table)
  454. PreANSI(Pint minint)
  455. PreANSI(Pint maxint)
  456. /*
  457. ** \blurb{Initialises table structure, containing hashtable, minuniqint,
  458. ** maxuniqint, freeintlist and stridtable.
  459. ** Function checks values of minint and maxint in case
  460. ** user gets them the wrong way round.}
  461. ** \param{table}{hashtable}
  462. ** \param{minint}{lower limit of string identifier range}
  463. ** \param{maxint}{upper limit of string identifier range}
  464. */
  465. {
  466.   Pint ind;
  467.  
  468.   for (ind = 0; ind < sizeofhashtable; ind++)
  469.     table->hashtable[ind] = NIL;
  470.   table->stridtable = (ptksstridentry *)malloc(sizeof(ptksstridentry));
  471.   table->numstrings = 0;
  472.   if (minint < maxint)
  473.   {
  474.     table->minuniqint = minint; /* minimum structure identifier */
  475.     table->maxuniqint = maxint; /* maximum structure identifier */
  476.   }
  477.   else
  478.   {
  479.     table->minuniqint = maxint; 
  480.     table->maxuniqint = minint ;
  481.   }
  482.   table->freeintlist = (ptksfreeint *)malloc(sizeof(ptksfreeint));
  483.   table->freeintlist->freeint = table->minuniqint;   /* first free id */
  484.   table->freeintlist->next = NULL;
  485. }  /* ptk_hashinitialise */
  486.  
  487. /*--------------------------------------------------------------------------*/
  488.  
  489. /*function:external*/
  490. extern void ptk_inithashtables(C(void))
  491. /* PreANSI() */
  492. /*
  493. ** \blurb{This function initialises the table in which the details of
  494. ** hashtables created by the application are kept. This function 
  495. ** must be called before any other hashtable functions.}
  496. */
  497. {
  498.   Pint ind;
  499.  
  500.   for (ind = 0; ind < sizeofhashtable; ind++)
  501.     toptable.hashtable[ind] = NIL;
  502.   toptable.tablelist = (ptkstableentry *)malloc(sizeof(ptkstableentry));
  503.   toptable.numtables = 0;
  504.   toptable.freeintlist = (ptksfreeint *)malloc(sizeof(ptksfreeint));
  505.   toptable.freeintlist->freeint = 0;   /* first free id */
  506.   toptable.freeintlist->next = NULL;
  507.   PTKINITHASH = TRUE;
  508. }  /* ptk_inithashtables */
  509.  
  510. /*--------------------------------------------------------------------------*/
  511.  
  512. /*function:external*/
  513. extern ptkboolean ptk_hashtableused(C(char *)str)
  514. PreANSI(char *str)
  515. /*
  516. ** \parambegin
  517. ** \param{char *}{str}{name of hashtable}{IN}
  518. ** \paramend
  519. ** \blurb{This function checks if a hashtable named \pardesc{str}
  520. ** already exists in the table of
  521. ** hashtables, returning TRUE if the hashtable exists, otherwise FALSE.}
  522. */
  523. {
  524.   Pint hashvalue, strlength;
  525.   char *newstr;
  526.   ptkboolean found;
  527.   Pint foundentry;
  528.  
  529.   if (!PTKINITHASH)
  530.     return FALSE;
  531.   strlength = stringlength(str);
  532.   newstr = (char *)malloc(strlength + 1);
  533.   parsestring(str, newstr, strlength);
  534.   hashvalue = hashstring(newstr, strlength);   /* calc hashvalue */
  535.   if (toptable.hashtable[hashvalue - 1] == NIL)
  536.   {   
  537.     /* not present */
  538.     return FALSE;
  539.   }
  540.   else 
  541.   {
  542.     /* collision, so traverse clash pointers to search for occurence */
  543.     searchfortable(newstr, toptable.hashtable[hashvalue - 1],
  544.                    &foundentry, &found);
  545.     return found;
  546.   }
  547. }  /* ptk_hashtableused */
  548.  
  549. /*--------------------------------------------------------------------------*/
  550.  
  551. /*function:external*/
  552. extern void ptk_createhashtable(C(char *) tablestr, C(Pint) minint, 
  553.                                 C(Pint) maxint)
  554. PreANSI(char *tablestr)
  555. PreANSI(Pint minint)
  556. PreANSI(Pint maxint)
  557. /*
  558. ** \parambegin
  559. ** \param{char *}{tablestr}{hashtable name}{IN}
  560. ** \param{Pint}{minint}{lower limit of string-integer range}{IN}
  561. ** \param{Pint}{maxint}{upper limit of string-integer range}{IN}
  562. ** \paramend
  563. ** \blurb{This function creates a new hashtable, with the name \pardesc{tablestr}. 
  564. ** \pardesc{minint} and \pardesc{maxint} respectively specify the lower and 
  565. ** upper limits of the range of 
  566. ** integers to which strings hashed into the hashtable will be mapped.}
  567. */
  568. {
  569.   Pint hashvalue, stid, strlength;
  570.   char *newstr;
  571.   ptkboolean found;
  572.   Pint foundentry;
  573.  
  574.   if (!PTKINITHASH)
  575.   {
  576.     fprintf(stderr, "HashStrings: Hashtables have not been initialised\n");
  577.     return;
  578.   }
  579.   /* check if string exists in top table */
  580.   if (!ptk_hashtableused(tablestr))
  581.   {
  582.     /* addstringtotable */
  583.     
  584.     strlength = stringlength(tablestr);
  585.     newstr = (char *)malloc(strlength + 1); /* `+1' for \0 character */
  586.     parsestring(tablestr, newstr, strlength);
  587.     hashvalue = hashstring(newstr, strlength);   /* calc hashvalue */
  588.     if (toptable.hashtable[hashvalue - 1] == NIL)
  589.     {  
  590.       /* no collision, so add string */
  591.       stid = addtabletotable(newstr);
  592.       toptable.hashtable[hashvalue - 1] = stid;
  593.       free(newstr);
  594.     } 
  595.     else 
  596.     {
  597.       /* collision, so traverse clash pointers to first free position */
  598.       searchfortable(newstr, toptable.hashtable[hashvalue - 1],
  599.                      &foundentry, &found);
  600.  
  601.       /* add into table */
  602.       stid = addtabletotable(newstr);
  603.       toptable.hashtable[hashvalue - 1] = stid; 
  604.       toptable.tablelist[foundentry].clashptr = stid;
  605.       toptable.tablelist[stid].prevptr = foundentry;
  606.       free(newstr);
  607.     }  /* else */
  608.  
  609.     toptable.tablelist[stid].tableptr = 
  610.                       (ptkshashtable *)malloc(sizeof(ptkshashtable));
  611.     ptk_hashinitialise(toptable.tablelist[stid].tableptr, minint, maxint);
  612.   }
  613. }  /* ptk_createhashtable */
  614.  
  615. /*--------------------------------------------------------------------------*/
  616.  
  617. static ptkshashtable * ptk_stringtotable(C(char *)str)
  618. PreANSI(char *str)
  619. /*
  620. ** \parambegin
  621. ** \param{char *}{str}{name of hashtable}{IN}
  622. ** \paramend
  623. ** \blurb{Returns pointer to a hashtable.}
  624. */
  625. {
  626.   Pint hashvalue, strlength;
  627.   char *newstr;
  628.   ptkboolean found;
  629.   Pint foundentry;
  630.  
  631.   strlength = stringlength(str);
  632.   newstr = (char *)malloc(strlength + 1); /* `+1' for \0 character */
  633.   parsestring(str, newstr, strlength);
  634.   hashvalue = hashstring(newstr, strlength);   /* calc hashvalue */
  635.   if (toptable.hashtable[hashvalue - 1] == NIL)
  636.   {  
  637.     /* no collision, so no table */
  638.     free(newstr);
  639.     fprintf(stderr, "HashStrings: Hashtable \"%s\" doesn't exist\n", str);
  640.     return NULL;
  641.   } 
  642.   else 
  643.   {
  644.     /* collision, so traverse clash pointers to first free position */
  645.     searchfortable(newstr, toptable.hashtable[hashvalue - 1],
  646.                    &foundentry, &found);
  647.     free(newstr); 
  648.     return toptable.tablelist[foundentry].tableptr;
  649.   }  /* else */
  650. }  /* ptk_stringtotable */
  651.  
  652. /*--------------------------------------------------------------------------*/
  653.  
  654. /*function:external*/
  655. extern void ptk_inttostring(C(char *) tablestr, C(Pint) stint, 
  656.                            C(Pint) size, C(char *) strbuffer, 
  657.                            C(Pint *) buffersize)
  658. PreANSI(char *tablestr)
  659. PreANSI(Pint stint)
  660. PreANSI(Pint size)
  661. PreANSI(char *strbuffer)
  662. PreANSI(Pint *buffersize)
  663. /*
  664. ** \parambegin
  665. ** \param{char *}{tablestr}{hashtable name}{IN}
  666. ** \param{Pint}{stint}{string identifier to search hashtable for}{IN}
  667. ** \param{Pint}{size}{number of bytes allocated by the user for the string}{IN}
  668. ** \param{char *}{strbuffer}{pointer to space allocated by the user for the string}{OUT}
  669. ** \param{Pint *}{buffersize}{actual size of buffer required}{OUT}
  670. ** \paramend
  671. ** \blurb{This function returns the string in hashtable \pardesc{tablestr}
  672. ** which has been allocated the integer
  673. ** \pardesc{stint}. The string is returned in the buffer \pardesc{strbuffer},
  674. ** which must be allocated by the application. The number of bytes actually used
  675. ** in the buffer is returned in \pardesc{buffersize}, as
  676. ** the length of string + 1 (for `\\0' character),
  677. ** or 0 if no string was returned.}
  678. */ 
  679. {
  680.   ptksstridentry *strentry;
  681.   ptkshashtable *table;
  682.   Pint i;
  683.   ptkboolean found;
  684.  
  685.   if ((table = ptk_stringtotable(tablestr)) != NULL)
  686.   {
  687.     found = FALSE;
  688.     i = 0;
  689.     while ((i < table->numstrings) && (!found))
  690.     {
  691.       strentry = &table->stridtable[i];
  692.       if ((strentry->uniqint == stint) && (strentry->strdata != NULL))
  693.         found = TRUE;
  694.       else
  695.         i++;
  696.     }
  697.  
  698.     if (!found)
  699.     {  
  700.       /* no string allocated */
  701.       *buffersize = 0;
  702.       return;
  703.     }
  704.     else
  705.     {
  706.       *buffersize = (strentry->stringlen + 1); 
  707.   
  708.       /* check buffer size */
  709.       if (size >= *buffersize)
  710.       {
  711.         /* copy string into buffer.
  712.         ** NB: this routine relies on the user being truthful about the
  713.         ** size of the buffer, if not errors may occur. 
  714.         */
  715.         strncpy(strbuffer, strentry->strdata, *buffersize);
  716.       }
  717.     }
  718.   }
  719. }  /* ptk_inttostring */
  720.  
  721. /*--------------------------------------------------------------------------*/
  722.  
  723. /*function:external*/
  724. extern Pint ptk_stringtoint(C(char *) tablestr, C(char *) str)
  725. PreANSI(char *tablestr)
  726. PreANSI(char *str)
  727. /*
  728. ** \parambegin
  729. ** \param{char *}{tablestr}{name of hashtable}{IN}
  730. ** \param{char *}{str}{string to be searched for in string table}{IN}
  731. ** \paramend
  732. ** \blurb{This function returns the integer allocated for the string \pardesc{str}
  733. ** in hashtable \pardesc{tablestr}.
  734. ** If the string has not already been allocated an integer,
  735. ** then it is allocated one and this value is 
  736. ** returned.}
  737. */
  738. {
  739.   Pint hashvalue, stid, strlength;
  740.   char *newstr;
  741.   ptkboolean found;
  742.   Pint foundentry;
  743.   ptkshashtable *table;
  744.  
  745.   if ((table = ptk_stringtotable(tablestr)) != NULL)
  746.   {
  747.     strlength = stringlength(str);
  748.     newstr = (char *)malloc(strlength + 1); /* `+1' for \0 character */
  749.     parsestring(str, newstr, strlength);
  750.     hashvalue = hashstring(newstr, strlength);   /* calc hashvalue */
  751.     if (table->hashtable[hashvalue - 1] == NIL)
  752.     {  
  753.       /* no collision, so add string */
  754.       if (addstringtotable(table, newstr, &stid))
  755.         table->hashtable[hashvalue - 1] = stid - table->minuniqint;
  756.       free(newstr);
  757.       return stid;
  758.     } 
  759.     else 
  760.     {
  761.       /* collision, so traverse clash pointers to first free position */
  762.       searchforstring(newstr, table->hashtable[hashvalue - 1],
  763.                       table, &foundentry, &found);
  764.       if (found)
  765.       {
  766.         free(newstr); 
  767.         return table->stridtable[foundentry].uniqint;   
  768.         /* string already present */
  769.       }
  770.       else 
  771.       {  
  772.         /* add into table */
  773.         if (addstringtotable(table, newstr, &stid))
  774.     {
  775.           table->hashtable[hashvalue - 1] = stid - table->minuniqint;
  776.           table->stridtable[stid - table->minuniqint].prevptr = foundentry;
  777.           table->stridtable[foundentry].clashptr = stid - table->minuniqint;
  778.         }
  779.         free(newstr);
  780.         return stid;
  781.       }  /* else */
  782.     }  /* else */
  783.   }
  784. }  /* ptk_stringtoint */
  785.  
  786. /*--------------------------------------------------------------------------*/
  787.  
  788. /*function:external*/
  789. extern ptkboolean ptk_delstring(C(char *) tablestr, C(char *) delstr)
  790. PreANSI(char *tablestr)
  791. PreANSI(char *delstr)
  792. /*
  793. ** \parambegin
  794. ** \param{char *}{tablestr}{name of hashtable}{IN}
  795. ** \param{char *}{delstr}{string to be deleted from string table}{IN}
  796. ** \paramend
  797. ** \blurb{This function deletes the string \pardesc{delstr} from hashtable
  798. ** \pardesc{tablestr}. The result of the function is
  799. **  TRUE if the string was, otherwise FALSE.}
  800. */ 
  801. {
  802.   Pint hashvalue, strlength;
  803.   char *newstr;
  804.   ptkboolean found;
  805.   ptksstridentry *strentry;
  806.   Pint foundentry;
  807.   ptkshashtable *table;
  808.  
  809.   if ((table = ptk_stringtotable(tablestr)) != NULL)
  810.   {
  811.     strlength = stringlength(delstr);
  812.     newstr = (char *)malloc(strlength + 1);
  813.     parsestring(delstr, newstr, strlength);
  814.     hashvalue = hashstring(newstr, strlength);
  815.     searchforstring(newstr, table->hashtable[hashvalue - 1], table,
  816.             &foundentry, &found);
  817.     if (!found)
  818.     { 
  819.       free(newstr);  
  820.       /* string not present */
  821.       return FALSE;
  822.     }
  823.     else 
  824.     {
  825.       free(newstr);
  826.       strentry = &table->stridtable[foundentry];
  827.       if (strentry->prevptr == NIL) 
  828.       {  
  829.         /* entry at head of list */
  830.         if (strentry->clashptr == NIL)   /* only one entry */
  831.           table->hashtable[hashvalue - 1] = NIL;
  832.         else 
  833.         {  
  834.           /* more than one entry in list */
  835.           table->stridtable[(strentry->clashptr)].prevptr = NIL;
  836.   
  837.           /* by-pass deleted entry 
  838.           table->hashtable[hashvalue - 1] = strentry->clashptr; */
  839.         }
  840.       }  /* if */
  841.       else 
  842.       if (strentry->clashptr == NIL) /* at end of list */
  843.       {
  844.         table->hashtable[hashvalue - 1] = strentry->prevptr;
  845.         table->stridtable[(strentry->prevptr)].clashptr = NIL;
  846.       }
  847.       else 
  848.       { 
  849.         /* in middle of list, so by-pass entry */
  850.         table->stridtable[(strentry->prevptr)].clashptr = 
  851.                                                   strentry->clashptr;
  852.         table->stridtable[(strentry->clashptr)].prevptr = 
  853.                                                   strentry->prevptr;
  854.       }
  855.       free(table->stridtable[foundentry].strdata);   /* retrieve id */
  856.       table->stridtable[foundentry].strdata = NULL;
  857.       table->stridtable[foundentry].clashptr = NIL;
  858.       table->stridtable[foundentry].prevptr = NIL;
  859.       freestrid(&table->freeintlist, table->stridtable[foundentry].uniqint);
  860.       return TRUE;
  861.     } 
  862.   }
  863. }  /* ptk_delstring */
  864.  
  865. /*--------------------------------------------------------------------------*/
  866.  
  867. /*function:external*/
  868. extern ptkboolean ptk_delhashtable(C(char *) tablestr)
  869. PreANSI(char *tablestr)
  870. /*
  871. ** \parambegin
  872. ** \param{char *}{tablestr}{name of table to be deleted}{IN}
  873. ** \paramend
  874. ** \blurb{This function deletes hastable \pardesc{tablestr} from the
  875. **  table of hashtables,
  876. **  returning TRUE if the table was deleted, otherwise FALSE.}
  877. */ 
  878. {
  879.   Pint hashvalue, strlength;
  880.   char *newstr;
  881.   ptkboolean found;
  882.   Pint foundentry;
  883.   ptkshashtable *delptr;
  884.   ptkstableentry *tabentry;
  885.   ptksfreeint *freeptr, *nextptr;
  886.   Pint i;
  887.  
  888.   strlength = stringlength(tablestr);
  889.   newstr = (char *)malloc(strlength + 1); /* `+1' for \0 character */
  890.   parsestring(tablestr, newstr, strlength);
  891.   hashvalue = hashstring(newstr, strlength);   /* calc hashvalue */
  892.   if (toptable.hashtable[hashvalue - 1] == NIL)
  893.   {  
  894.     /* no collision, so no table */
  895.     free(newstr);
  896.     return FALSE;
  897.   } 
  898.   else 
  899.   {
  900.     /* collision, so traverse clash pointers to first free position */
  901.     searchfortable(newstr, toptable.hashtable[hashvalue - 1],
  902.                    &foundentry, &found);
  903.  
  904.     /* get pointer to hashtable */
  905.  
  906.     delptr = toptable.tablelist[foundentry].tableptr;
  907.  
  908.     /* delete each string in hashtable */
  909.  
  910.     /* free string table */
  911.  
  912.     for (i = 0; i < delptr->numstrings; i++)
  913.     {
  914.       free(delptr->stridtable[i].strdata);
  915.       free(delptr->stridtable[i]);
  916.     }
  917.  
  918.     /* free freeintlist */
  919.     freeptr = delptr->freeintlist;
  920.     if (freeptr != NULL)
  921.     { 
  922.       nextptr = freeptr->next;
  923.       free(freeptr);
  924.       freeptr = nextptr;
  925.     }
  926.  
  927.     /* free ptkshashtable */
  928.     
  929.     free(delptr);
  930.     
  931.     toptable.tablelist[foundentry].tableptr = NULL;
  932.  
  933.     /* delete tableentry from ptkshashtablelst */
  934.  
  935.     tabentry = &toptable.tablelist[foundentry];
  936.     if (tabentry->prevptr == NIL) 
  937.     {  
  938.       /* entry at head of list */
  939.       if (tabentry->clashptr == NIL)   /* only one entry */
  940.         toptable.hashtable[hashvalue - 1] = NIL;
  941.       else 
  942.       {  
  943.         /* more than one entry in list */
  944.     toptable.tablelist[(tabentry->clashptr)].prevptr = NIL;
  945.  
  946.     /* by-pass deleted entry 
  947.         toptable.hashtable[hashvalue - 1] = tabentry->clashptr; */
  948.       }
  949.     }  /* if */
  950.     else
  951.     if (tabentry->clashptr == NIL) /* at end of list */
  952.     {
  953.       toptable.tablelist[(tabentry->prevptr)].clashptr = NIL;
  954.       toptable.hashtable[hashvalue - 1] = tabentry->prevptr;
  955.     }
  956.     else 
  957.     { 
  958.       /* in middle of list, so by-pass entry */
  959.       toptable.tablelist[(tabentry->prevptr)].clashptr = 
  960.                                                   tabentry->clashptr;
  961.       toptable.tablelist[(tabentry->clashptr)].prevptr = 
  962.                                                   tabentry->prevptr;
  963.     }
  964.     free(toptable.tablelist[foundentry].strdata);   /* retrieve id */
  965.     toptable.tablelist[foundentry].strdata = NULL;
  966.     toptable.tablelist[foundentry].clashptr = NIL;
  967.     toptable.tablelist[foundentry].prevptr = NIL;
  968.     free(newstr); 
  969.     return TRUE;
  970.   }  /* else */
  971. }  /* ptk_delhashtable */
  972.  
  973. /*--------------------------------------------------------------------------*/
  974.  
  975. /*function:external*/
  976. extern ptkboolean ptk_stringused(C(char *) tablestr, C(char *) str)
  977. PreANSI(char *tablestr)
  978. PreANSI(char *str)
  979. /*
  980. ** \parambegin
  981. ** \param{char *}{tablestr}{name of hashtable}{IN}
  982. ** \param{char *}{str}{string to search for in string table}{IN}
  983. ** \paramend
  984. ** \blurb{This function checks if the string \pardesc{str}
  985. **  has already been used in hashtable \pardesc{tablestr},
  986. ** Returning TRUE if string was used in the hashtable, otherwise FALSE.}
  987. */
  988. {
  989.   Pint hashvalue, strlength;
  990.   char *newstr;
  991.   ptkboolean found;
  992.   Pint foundentry;
  993.   ptkshashtable *table;
  994.  
  995.   if ((table = ptk_stringtotable(tablestr)) != NULL)
  996.   {
  997.     strlength = stringlength(str);
  998.     newstr = (char *)malloc(strlength + 1);
  999.     parsestring(str, newstr, strlength);
  1000.     hashvalue = hashstring(newstr, strlength);   /* calc hashvalue */
  1001.     if (table->hashtable[hashvalue - 1] == NIL)
  1002.     {   
  1003.       /* not present */
  1004.       return FALSE;
  1005.     }
  1006.     else 
  1007.     {
  1008.       /* collision, so traverse clash pointers to search for occurence */
  1009.       searchforstring(newstr, table->hashtable[hashvalue - 1], table,
  1010.                       &foundentry, &found);
  1011.       return found;
  1012.     }
  1013.   }
  1014. }  /* ptk_stringused */
  1015.  
  1016. /*--------------------------------------------------------------------------*/
  1017.  
  1018. /*function:external*/
  1019. extern void ptk_inqstrings(C(char *) tablestr, C(Pint) size, 
  1020.                            C(Pint *) totalsize, C(char *) strbuffer,
  1021.                            C(ptksstringtable *) strtable)
  1022.  
  1023. PreANSI(char *tablestr)
  1024. PreANSI(Pint size)
  1025. PreANSI(Pint *totalsize)
  1026. PreANSI(char *strbuffer)
  1027. PreANSI(ptksstringtable *strtable)
  1028. /*
  1029. ** \parambegin
  1030. ** \param{char *}{tablestr}{name of hashtable}{IN}
  1031. ** \param{Pint}{size}{number of bytes allocated by the user for string table data.}{IN}
  1032. ** \param{Pint *}{totalsize}{actual size of buffer required for string table data.}{OUT}
  1033. ** \param{char *}{strbuffer}{application supplied buffer for string table data}{OUT}
  1034. ** \param{ptksstringtable *}{strtable}{struct containing length of arrays and pointer to data in strbuffer.}{OUT}
  1035. ** \paramend
  1036. ** \blurb{This function is used to interogate hashtable \pardesc{tablestr}.
  1037. ** A list of the \pardesc{size} strings contained in the hashtable are returned
  1038. ** in the user specified buffer \pardesc{strbuffer}, together with their
  1039. ** corresponding
  1040. ** string lengths and integer hash values.}
  1041. */
  1042. {
  1043.   Pint ind;
  1044.   ptksstridentry *strentry;
  1045.   Pint *stidptr;
  1046.   Pint *strlenptr;
  1047.   char **strptr;
  1048.   char *stringptr;
  1049.   Pint counter = 0;
  1050.   ptkshashtable *table;
  1051.  
  1052.   if ((table = ptk_stringtotable(tablestr)) != NULL)
  1053.   {
  1054.     *totalsize = 0;
  1055.     for (ind = 0; ind < table->numstrings; ind++) 
  1056.     {
  1057.       strentry = (table->stridtable + ind);
  1058.       if (strentry->strdata != NULL)
  1059.       { 
  1060.         *totalsize += (2 * sizeof(Pint)) + sizeof(char *) + 
  1061.                       (strentry->stringlen + 1);
  1062.         counter++;
  1063.       }  
  1064.     }
  1065.    
  1066.     strtable->listlen = counter;
  1067.     /* if application buffer is big enough, copy in data */
  1068.     if (counter > 0)
  1069.     {
  1070.       if ((size >= *totalsize) && (strbuffer != NULL))
  1071.       {
  1072.         /* pointers into application supplied buffer */
  1073.         stidptr = strtable->intlist = (Pint *)strbuffer;
  1074.         strlenptr = strtable->strlenlist = (Pint *)(strbuffer + 
  1075.                                   (counter * sizeof(Pint)));
  1076.         strptr = strtable->strlist = (char **)(strbuffer + 
  1077.                       (2 * (counter * sizeof(Pint))));
  1078.         stringptr = (char *)(strptr + (counter * sizeof(char *)));
  1079.         for (ind = 0; ind < table->numstrings; ind++)
  1080.         {  
  1081.           if ((table->stridtable + ind)->strdata != NULL) 
  1082.           {   
  1083.             strentry = (table->stridtable + ind);
  1084.             strncpy(stringptr, strentry->strdata, 
  1085.                     (strentry->stringlen + 1));
  1086.             *strptr = (char *)stringptr;
  1087.             strptr++;
  1088.             stringptr += (strentry->stringlen + 2); 
  1089.             *strlenptr = (Pint)strentry->stringlen;
  1090.             strlenptr++;
  1091.             *stidptr = (Pint)strentry->uniqint;
  1092.             stidptr++; 
  1093.           }
  1094.         }
  1095.       }
  1096.     }
  1097.   }
  1098. }  /* ptk_inqstrings */
  1099.  
  1100. /*--------------------------------------------------------------------------*/
  1101.  
  1102. /*function:external*/
  1103. extern void ptk_inqhashtables(C(Pint) size, C(Pint *) totalsize, 
  1104.                            C(char *) strbuffer, C(ptkstablelist *) tablerec)
  1105. PreANSI(Pint size)
  1106. PreANSI(Pint *totalsize)
  1107. PreANSI(char *strbuffer)
  1108. PreANSI(ptkstablelist *tablerec)
  1109. /*
  1110. ** \parambegin
  1111. ** \param{Pint}{size}{number of bytes allocated for the hashtable data.}{IN}
  1112. ** \param{Pint *}{totalsize}{actual number of bytes required for hashtable data.}{OUT}
  1113. ** \param{char *}{strbuffer}{pointer to buffer for hashtable data}{OUT}
  1114. ** \param{ptkstablelist *}{tablerec}{hash table data.}{OUT}
  1115. ** \paramend
  1116. ** \blurb{This function returns in the
  1117. ** user specified buffer \pardesc{strbuffer} 
  1118. ** the names of each hashtable contained in the table of hashtables.}
  1119. */
  1120. {
  1121.   Pint ind;
  1122.   ptkstableentry *tabentry;
  1123.   Pint *strlenptr;
  1124.   char **strptr;
  1125.   char *stringptr;
  1126.   Pint counter = 0;
  1127.  
  1128.   *totalsize = 0;
  1129.   for (ind = 0; ind < toptable.numtables; ind++) 
  1130.   {
  1131.     tabentry = &toptable.tablelist[ind];
  1132.     if ((tabentry->tableptr) != NULL)
  1133.     { 
  1134.       *totalsize += sizeof(Pint) + sizeof(char *) + 
  1135.                     (tabentry->stringlen + 1);
  1136.       counter++;
  1137.     }  
  1138.   }
  1139.  
  1140.   tablerec->listlen = counter;
  1141.   /* if application buffer is big enough, copy in data */
  1142.   if (counter > 0)
  1143.   {
  1144.     if ((size >= *totalsize) && (strbuffer != NULL))
  1145.     {
  1146.       /* pointers into application supplied buffer */
  1147.       strlenptr = tablerec->namelenlist = (Pint *)(strbuffer);
  1148.       strptr = tablerec->tablenames = (char **)(strbuffer + 
  1149.                     (counter * sizeof(Pint)));
  1150.       stringptr = (char *)(strptr + (counter * sizeof(char *)));
  1151.       for (ind = 0; ind < toptable.numtables; ind++)
  1152.       {  
  1153.         tabentry = &toptable.tablelist[ind];    
  1154.         if (tabentry->tableptr != NULL) 
  1155.         {   
  1156.           strncpy(stringptr, tabentry->strdata, 
  1157.                   (tabentry->stringlen + 1));
  1158.           *strptr = (char *)stringptr;
  1159.           strptr++;
  1160.           stringptr += (tabentry->stringlen + 2); 
  1161.           *strlenptr = (Pint)tabentry->stringlen;
  1162.           strlenptr++;
  1163.         }
  1164.       }
  1165.     }
  1166.   }
  1167. }  /* ptk_inqhashtables */
  1168.  
  1169. /*--------------------------------------------------------------------------*/
  1170.  
  1171. static void outputfreeintlist(C(FILE *) f, C(ptksfreeint *) freeptr)
  1172. PreANSI(FILE *f)
  1173. PreANSI(ptksfreeint *freeptr)
  1174. /*
  1175. ** \parambegin
  1176. ** \param{ }{f}{pointer to a file}{IN}
  1177. ** \param{ }{freeptr}{free identifier list}{IN}
  1178. ** \paramend
  1179. ** \blurb{Outputs the free identifier list to a file in 
  1180. ** reverse order.}
  1181. */
  1182. {
  1183.   if (freeptr != NULL)
  1184.   { 
  1185.     outputfreeintlist(f, freeptr->next);
  1186.     fprintf(f, "%d\n", freeptr->freeint);
  1187.   }
  1188. }  /* outputfreeintlist */
  1189.  
  1190. /*--------------------------------------------------------------------------*/
  1191.  
  1192. /*function:external*/
  1193. extern void ptk_storehashtable(C(FILE *) fileptr, C(char *) tablestr)
  1194. PreANSI(FILE *fileptr)
  1195. PreANSI(char *tablestr)
  1196. /*
  1197. ** \parambegin
  1198. ** \param{FILE *}{fileptr}{pointer to a file}{IN}
  1199. ** \param{char *}{table}{hashtable to store}{IN}
  1200. ** \paramend
  1201. ** \blurb{The function writes the hashtable \pardesc{tablestr} to the
  1202. ** file \pardesc{fileptr}, which should be opened and writeable.}
  1203. */
  1204. {
  1205.   Pint ind;
  1206.   Pint numstrs;
  1207.   ptksfreeint *freeptr;
  1208.   ptksstridentry *strentry;
  1209.   ptkshashtable *table;
  1210.  
  1211.   if ((table = ptk_stringtotable(tablestr)) != NULL)
  1212.   {
  1213.     fprintf(fileptr, "start\n");
  1214.     /* output structure identifier range */
  1215.     fprintf(fileptr, "%d\n", table->minuniqint);
  1216.     fprintf(fileptr, "%d\n", table->maxuniqint);
  1217.     numstrs = 0;
  1218.     for (ind = 0; ind < table->numstrings; ind++) 
  1219.     {
  1220.       if ((table->stridtable + ind)->strdata != NULL) 
  1221.         numstrs++;
  1222.     }
  1223.     fprintf(fileptr, "%d\n", numstrs);
  1224.     /* output string table entries */
  1225.     for (ind = 0; ind < table->numstrings; ind++) 
  1226.     {
  1227.       if ((table->stridtable + ind)->strdata != NULL) 
  1228.       {   
  1229.         strentry = (table->stridtable + ind);
  1230.         fprintf(fileptr, "%d\n", (strentry->stringlen + 1));
  1231.         fprintf(fileptr, "%s\n", strentry->strdata);
  1232.         fprintf(fileptr, "%d\n", strentry->uniqint);
  1233.       }
  1234.     }
  1235.     /* output free identifiers, in reverse order */
  1236.     freeptr = table->freeintlist;
  1237.     outputfreeintlist(fileptr, freeptr);
  1238.     /* terminate table store with `end' */
  1239.     fprintf(fileptr, "end\n");
  1240.   }
  1241. }  /* ptk_storehashtable */
  1242.  
  1243. /*--------------------------------------------------------------------------*/
  1244.  
  1245. /*function:external*/
  1246. extern void ptk_storeallhashtables(C(FILE *) fileptr)
  1247. PreANSI(FILE *fileptr)
  1248. /*
  1249. ** \parambegin
  1250. ** \param{FILE *}{fileptr}{pointer to a file}{IN}
  1251. ** \paramend
  1252. ** \blurb{The function writes all the hashtables in the table of hashtables
  1253. ** to the
  1254. ** file \pardesc{fileptr}, which should be opened and writeable.}
  1255. */
  1256. {
  1257.   Pint i, count;
  1258.  
  1259.   count = 0;
  1260.   for (i = 0; i < toptable.numtables; i++)
  1261.     if (toptable.tablelist[i].tableptr != NULL) {count++;}
  1262.  
  1263.   /* number of hashtables */
  1264.   fprintf(fileptr, "%d\n", count);
  1265.  
  1266.   /* for each hashtable */
  1267.   for (i = 0; i < toptable.numtables; i++)
  1268.   {
  1269.     if (toptable.tablelist[i].tableptr != NULL)
  1270.     {
  1271.       fprintf(fileptr, "%s\n", toptable.tablelist[i].strdata);
  1272.       ptk_storehashtable(fileptr, toptable.tablelist[i].strdata);
  1273.     }
  1274.   }
  1275. }  /* ptk_storeallhashtables */
  1276.  
  1277. /*--------------------------------------------------------------------------*/
  1278.  
  1279. static void addstring(C(ptkshashtable *) table, C(Pint) strlength,
  1280.                       C(char *) str, C(Pint) stid)
  1281. PreANSI(ptkshashtable *table)
  1282. PreANSI(Pint strlength)
  1283. PreANSI(char *str)
  1284. PreANSI(Pint stid)
  1285. /*
  1286. ** \parambegin
  1287. ** \param{ }{table}{hashtable}{IN}
  1288. ** \param{ }{strlength}{length of string to add}{IN}
  1289. ** \param{ }{str}{string to be added in string table}{IN}
  1290. ** \param{ }{stid}{string identifier allocated to string}{IN}
  1291. ** \paramend
  1292. ** \blurb{Inserts the given parameters into a ptksstridentry
  1293. ** structure and sets up the pointers from the hashtable to the string
  1294. ** table and the clash pointers.}
  1295. */
  1296. {
  1297.   Pint hashvalue;
  1298.   ptkboolean found;
  1299.   Pint foundentry;
  1300.   Pint dumstid;
  1301.  
  1302.   hashvalue = hashstring(str, strlength);   /* calc hashvalue */
  1303.   if (table->hashtable[hashvalue - 1] == NIL)
  1304.   {  
  1305.     /* no collision, so add string */
  1306.     if (addstringtotable(table, str, &dumstid))
  1307.     {
  1308.       table->hashtable[hashvalue - 1] = dumstid - table->minuniqint;
  1309.       table->stridtable[dumstid - table->minuniqint].uniqint = stid;
  1310.     }
  1311.   } 
  1312.   else 
  1313.   {
  1314.     /* collision, so traverse clash pointers to first free position */
  1315.     searchforstring(str, table->hashtable[hashvalue - 1],
  1316.                     table, &foundentry, &found);
  1317.     if (!found)
  1318.     {  
  1319.       /* add into table */
  1320.       if (addstringtotable(table, str, &dumstid))
  1321.       {
  1322.         table->stridtable[foundentry].clashptr = dumstid - table->minuniqint;
  1323.         table->stridtable[dumstid - table->minuniqint].prevptr = foundentry;
  1324.         table->stridtable[dumstid - table->minuniqint].uniqint = stid;
  1325.       }
  1326.     }
  1327.   }  /* else */
  1328. }  /* addstring */
  1329.  
  1330. /*-------------------------------------------------------------------------*/
  1331.  
  1332. /*function:external*/
  1333. extern void ptk_restorehashtable(C(FILE *) fileptr, C(char *) tablestr)
  1334. PreANSI(FILE *fileptr)
  1335. PreANSI(char *tablestr)
  1336. /*
  1337. ** \parambegin
  1338. ** \param{FILE *}{fileptr}{pointer to a file}{IN}
  1339. ** \param{char *}{tablestr}{hashtable to insert data from file}{IN}
  1340. ** \paramend
  1341. ** \blurb{This function reads a hashtable from the file \pardesc{fileptr},
  1342. ** and creates it with the name \pardesc{tablestr}. If the hashtable already exists,
  1343. ** it is deleted, and then recreated from the file. The file should be open and
  1344. ** readable when this function is called.}
  1345. */
  1346. {
  1347. #define LINELEN  80
  1348.  
  1349.   Pint ind;
  1350.   Pint minint, maxint;
  1351.   Pint numstrs;
  1352.   Pint stringlen, uniqint;
  1353.   char *strdata;
  1354.   char *str;
  1355.   Pint id;
  1356.   ptkshashtable *table;
  1357.  
  1358.   /* check if table exists */
  1359.   if (ptk_hashtableused(tablestr))
  1360.   {
  1361.     ptk_delhashtable(tablestr);
  1362.   }
  1363.   str = (char *)malloc(LINELEN);
  1364.   fgets(str, LINELEN, fileptr);
  1365.  
  1366.   /* get structure identifier range */
  1367.   fgets(str, LINELEN, fileptr);
  1368.   minint = atoi(str);
  1369.   fgets(str, LINELEN, fileptr);
  1370.   maxint = atoi(str);
  1371.  
  1372.   /* create table to be restored */
  1373.   ptk_createhashtable(tablestr, minint, maxint);
  1374.   table = ptk_stringtotable(tablestr);
  1375.  
  1376.   /* get number of strings */
  1377.   fgets(str, LINELEN, fileptr);
  1378.   numstrs = atoi(str);
  1379.  
  1380.   /* input string table entries */
  1381.   for (ind = 0; ind < numstrs; ind++)
  1382.   {
  1383.     fgets(str, LINELEN, fileptr);
  1384.     stringlen = atoi(str);
  1385.     strdata = (char *)malloc(stringlen);
  1386.     fgets(str, LINELEN, fileptr);
  1387.     strncpy(strdata, str, stringlen);
  1388.     strdata[stringlen - 1] = '\0';
  1389.     fgets(str, LINELEN, fileptr);
  1390.     uniqint = atoi(str);
  1391.     addstring(table, (stringlen - 1), strdata, uniqint);
  1392.     free(strdata);
  1393.   }
  1394.   /* input free identifiers (stored in reverse order) */
  1395.   fgets(str, LINELEN, fileptr);
  1396.   id = atoi(str);
  1397.   table->freeintlist->freeint = id;
  1398.   fgets(str, LINELEN, fileptr);
  1399.   while (strncmp(str, "end", 3) != 0)
  1400.   {
  1401.     id = atoi(str);
  1402.     freestrid(&table->freeintlist, id);
  1403.     fgets(str, LINELEN, fileptr);
  1404.   } 
  1405.   free(str);
  1406. }  /* ptk_restorehashtable */
  1407.  
  1408. /*--------------------------------------------------------------------------*/
  1409.  
  1410. /*function:external*/
  1411. extern void ptk_restoreallhashtables(C(FILE *) fileptr)
  1412. PreANSI(FILE *fileptr)
  1413. /*
  1414. ** \parambegin
  1415. ** \param{FILE *}{fileptr}{pointer to a file}{IN}
  1416. ** \paramend
  1417. ** \blurb{This function restores all hashtables from a file. Effectively,
  1418. ** \pardesc{ptk\_restorehashtable} (q.v.) is called for each hashtable in
  1419. ** the file. The file should 
  1420. ** be open and
  1421. ** readable when this function is called.}
  1422. */
  1423. {
  1424.   Pint i, numtables;
  1425.   char tablename[255];
  1426.   
  1427.   fscanf(fileptr, "%d\n", &numtables);
  1428.  
  1429.   /* for each hashtable in file */
  1430.   for (i = 0; i < numtables; i++)
  1431.   {
  1432.     fscanf(fileptr, "%s\n", tablename);
  1433.     ptk_restorehashtable(fileptr, tablename);
  1434.   }    
  1435. }  /* ptk_restoreallhashtables */
  1436.  
  1437. /*--------------------------------------------------------------------------*/
  1438.  
  1439. /* end of hash.c */
  1440.